﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Xml;
using System.Xml.Linq;
using ThePingMasterConfiguration.Commands;

namespace ThePingMasterConfiguration.ViewModels
{
    public class ConfigurationModel : INotifyPropertyChanged
    {
        private const string DuplicateAddressMessage = "Address is already in the list.";
        public const string ConfigurationFilename = @"./config.xml";

        public ConfigurationModel() : this(new CommandFactory())
        {
            
        }

        public ConfigurationModel(ICommandFactory factory)
        {
            Load();

            SaveCommand = factory.GetSaveCommand(this);
            QuitCommand = factory.GetQuitCommand();
            BrowseSuccessCommand = factory.GetBrowseSuccessCommand(this);
            BrowseFailureCommand = factory.GetBrowseFailureCommand(this);
            AboutCommand = factory.GetAboutCommand();
            RemoveAddressCommand = factory.GetRemoveAddressCommand(this);
            AddAddressCommand = factory.GetAddAddressCommand(this);
            DuplicateAddressCommand = factory.GetDuplicateAddressCommand(DuplicateAddressMessage);
        }

        private void Load()
        {
            XDocument document = XDocument.Load(new XmlTextReader(ConfigurationFilename));
            OnSuccess = document.Root.Attribute("onSuccess").Value;
            OnSuccessParams = document.Root.Attribute("onSuccessParams").Value;
            OnFailure = document.Root.Attribute("onFailure").Value;
            OnFailureParams = document.Root.Attribute("onFailureParams").Value;
            Interval = int.Parse(document.Root.Attribute("interval").Value) / 1000;
            Timeout = int.Parse(document.Root.Attribute("timeout").Value) / 1000;
            RetryAttemptsBeforeFailure = int.Parse(document.Root.Attribute("retryAttemptsBeforeFailure").Value);
            RetryOnNetworkException = bool.Parse(document.Root.Attribute("retryOnNetworkException").Value);
            Addresses = new ObservableCollection<string>();
            foreach(XElement addressElement in document.Root.Elements("address"))
            {
                Addresses.Add(addressElement.Value);
            }
        }

        public void Save()
        {
            XDocument document = new XDocument(
                new XElement("config",
                    new XAttribute("onSuccess", OnSuccess),
                    new XAttribute("onSuccessParams", OnSuccessParams),
                    new XAttribute("onFailure", OnFailure),
                    new XAttribute("onFailureParams", OnFailureParams),
                    new XAttribute("interval", Interval*1000),
                    new XAttribute("timeout", Timeout*1000),
                    new XAttribute("retryAttemptsBeforeFailure", RetryAttemptsBeforeFailure),
                    new XAttribute("retryOnNetworkException", RetryOnNetworkException),
                    Addresses.Select(a => new XElement("address", a))
                    )
                );
            document.Save(ConfigurationFilename);
        }

        #region Configuration properties

        private string _onSuccess;
        public string OnSuccess
        {
            get { return _onSuccess; }
            set { _onSuccess = value; OnPropertyChanged("OnSuccess"); }
        }

        public string OnSuccessParams { get; set; }

        private string _onFailure;
        public string OnFailure
        {
            get { return _onFailure; }
            set { _onFailure = value; OnPropertyChanged("OnFailure"); }
        }

        public string OnFailureParams { get; set; }

        public int Interval { get; set; }

        public int Timeout { get; set; }

        public int RetryAttemptsBeforeFailure { get; set; }

        public ObservableCollection<string> Addresses { get; set; }

        public string SelectedAddress { get; set; }

        public bool RetryOnNetworkException { get; set; }

        #endregion

        #region Commands

        public SaveCommand SaveCommand { get; private set; }

        public QuitCommand QuitCommand { get; private set; }

        public BrowseSuccessCommand BrowseSuccessCommand { get; set; }

        public BrowseFailureCommand BrowseFailureCommand { get; set; }

        public AboutCommand AboutCommand { get; set; }

        public RemoveAddressCommand RemoveAddressCommand { get; set; }

        public AddAddressCommand AddAddressCommand { get; set; }

        public MessageCommand DuplicateAddressCommand { get; set; }

        #endregion

        public bool Validate()
        {
            return true;
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void AddAddress(string newAddress)
        {
            if (Addresses.Contains(newAddress))
            {
                DuplicateAddressCommand.Execute(null);
            }
            else
            {
                Addresses.Add(newAddress);
            }
        }
    }
}
